package com.naiterui.ehp.bs.recommend.service.impl;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.imageio.ImageIO;

import com.naiterui.ehp.bs.recommend.vo.require.DrRequireListVO;
import com.naiterui.ehp.bs.recommend.vo.require.DrRequireSkuListVO;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.naiterui.common.redis.RedisUtil;
import com.naiterui.common.repository.page.JpaPageConvertor;
import com.naiterui.common.repository.page.PageParamVO;
import com.naiterui.common.repository.page.PageVO;
import com.naiterui.ehp.bp.bo.cms.DrRecordAuthorityBO;
import com.naiterui.ehp.bp.bo.doctor.RecomDoctorBO;
import com.naiterui.ehp.bp.bo.doctor.RecomPatientBO;
import com.naiterui.ehp.bp.bo.doctor.RecomPatientBO.AgeUnitEunm;
import com.naiterui.ehp.bp.bo.doctor.RecomUserInfoBO;
import com.naiterui.ehp.bp.bo.emr.MedicalRecordBO;
import com.naiterui.ehp.bp.bo.emr.MedicalRecordDoctorBO;
import com.naiterui.ehp.bp.bo.recommend.DrBaseBusinessDataBO;
import com.naiterui.ehp.bp.bo.recommend.DrPointPrescriptionBO;
import com.naiterui.ehp.bp.bo.recommend.MedicationRecomBO;
import com.naiterui.ehp.bp.bo.recommend.MedicationRecomItemBO;
import com.naiterui.ehp.bp.bo.recommend.MedicationRecomItemPaBO;
import com.naiterui.ehp.bp.bo.recommend.MedicationRecomPaBO;
import com.naiterui.ehp.bp.bo.recommend.PrescriptionPlatformRecomInfoBO;
import com.naiterui.ehp.bp.bo.recommend.RecomOrderInfoBO;
import com.naiterui.ehp.bp.bo.recommend.RecomPrescriptionBO;
import com.naiterui.ehp.bp.bo.recommend.param.RecomBuyNotifyParamBO;
import com.naiterui.ehp.bp.bo.recommend.param.RecomInfoParamBO;
import com.naiterui.ehp.bp.bo.statistics.AsRecipelRecordBO;
import com.naiterui.ehp.bp.constants.CommonConstant;
import com.naiterui.ehp.bp.constants.DoctorPatientRelation;
import com.naiterui.ehp.bp.constants.MedicationRecomInvalidStatusEnum;
import com.naiterui.ehp.bp.constants.MedicationRecomSourceTypeEnum;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.support.utils.JsonMapper;
import com.naiterui.ehp.bp.utils.beans.BeanUtil;
import com.naiterui.ehp.bp.utils.date.DateUtil;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bp.utils.lang.StringUtil;
import com.naiterui.ehp.bp.utils.thread.ThreadPoolUtil;
import com.naiterui.ehp.bs.recommend.bean.DrMedicationRecomDiagnosis;
import com.naiterui.ehp.bs.recommend.bean.DrMedicationRecomInfo;
import com.naiterui.ehp.bs.recommend.bean.DrStandardDiagnosis;
import com.naiterui.ehp.bs.recommend.bean.MedicationRecom;
import com.naiterui.ehp.bs.recommend.bean.MedicationRecomDetail;
import com.naiterui.ehp.bs.recommend.bean.MedicationRequire;
import com.naiterui.ehp.bs.recommend.bean.RecomAuditLog;
import com.naiterui.ehp.bs.recommend.bean.RecomPrescription;
import com.naiterui.ehp.bs.recommend.exception.ExceptionCodes;
import com.naiterui.ehp.bs.recommend.remote.IB2cFeignClient;
import com.naiterui.ehp.bs.recommend.remote.IDoctorFeignClient;
import com.naiterui.ehp.bs.recommend.remote.IPatientFeignClient;
import com.naiterui.ehp.bs.recommend.remote.IRecommendRemoter;
import com.naiterui.ehp.bs.recommend.remote.ISearchFeignClient;
import com.naiterui.ehp.bs.recommend.remote.VideoConsultFeignClient;
import com.naiterui.ehp.bs.recommend.repository.mysql.IDrStandardDiagnosisRepository;
import com.naiterui.ehp.bs.recommend.repository.mysql.IMedicationRecomDetailRepository;
import com.naiterui.ehp.bs.recommend.repository.mysql.IMedicationRecomDiagnosisRepository;
import com.naiterui.ehp.bs.recommend.repository.mysql.IMedicationRecomInfoRepository;
import com.naiterui.ehp.bs.recommend.repository.mysql.IMedicationRecomRepository;
import com.naiterui.ehp.bs.recommend.repository.mysql.IMedicationRequireRepository;
import com.naiterui.ehp.bs.recommend.repository.mysql.IRecomAuditLogRepository;
import com.naiterui.ehp.bs.recommend.repository.mysql.IRecommPrescriptionRepository;
import com.naiterui.ehp.bs.recommend.service.IRecomCreaterService;
import com.naiterui.ehp.bs.recommend.service.IRecomDetailService;
import com.naiterui.ehp.bs.recommend.service.IRecomMessageService;
import com.naiterui.ehp.bs.recommend.service.IRecomService;
import com.naiterui.ehp.bs.recommend.util.Constants;
import com.naiterui.ehp.bs.recommend.util.Constants.RecomStatusEunm;
import com.naiterui.ehp.bs.recommend.util.RecomBizUtil;
import com.naiterui.ehp.bs.recommend.util.SMSUtil;
import com.naiterui.ehp.bs.recommend.util.SMSUtil.Template;
import com.naiterui.ehp.bs.recommend.vo.MedicationBoxVO;
import com.naiterui.ehp.bs.recommend.vo.MedicationBoxWithUsageVO;
import com.naiterui.ehp.bs.recommend.vo.MedicationPrescriptionVO;
import com.naiterui.ehp.bs.recommend.vo.MedicationRecomDetailVO;
import com.naiterui.ehp.bs.recommend.vo.PatientNameVO;
import com.naiterui.ehp.bs.recommend.vo.RecomDetailVO;
import com.naiterui.ehp.bs.recommend.vo.RecomLiteVO;
import com.naiterui.ehp.bs.recommend.vo.RecomRecordVO;
import com.naiterui.ehp.bs.recommend.vo.RecomSkuVO;
import com.naiterui.ehp.bs.recommend.vo.dto.IMRecomRemindDTO;

import cn.hutool.core.collection.CollUtil;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class RecomServiceImpl implements IRecomService {

    private static Logger LOGGER = LoggerFactory.getLogger(RecomServiceImpl.class);

    @Autowired
    private IRecommendRemoter remoter;
    @Autowired
    private IMedicationRecomRepository medicationRecomRepository;
    @Autowired
    private IMedicationRecomInfoRepository medicationRecomInfoRepository;
    @Autowired
    private IMedicationRecomDetailRepository medicationRecomDetailRepository;
    @Autowired
    private IRecomDetailService recomDetailService;
    @Autowired
    private IMedicationRecomDiagnosisRepository medicationRecomDiagnosisRepository;
    @Autowired
    private IRecomCreaterService recomCreaterService;
    @Autowired
    private IDrStandardDiagnosisRepository drStandardDiagnosisRepository;

    @Autowired
    private IRecomMessageService recomMessageService;
    @Autowired
    private IMedicationRequireRepository medicationRequireRepository;
    @Autowired
    private IRecommPrescriptionRepository recomPrescriptionRepository;

    @Autowired
    private IPatientFeignClient patientFeignClient;
    @Autowired
    private IRecommPrescriptionRepository recommPrescriptionRepository;
    @Autowired
    private IDoctorFeignClient doctorFeignClient;
    @Value("${ehp.domain.img}")
    private String imgDomain;

    @Autowired
    private IRecomAuditLogRepository recomAuditLogRepository;

    @Autowired
    private VideoConsultFeignClient videoConsultFeignClient;
    @Autowired
    private IB2cFeignClient ib2cFeignClient;
    @Autowired
    private ISearchFeignClient searchFeignClient;

    private static String RECOM_DELETE_DIAGNOSE_TIP = ConfigUtil.getString("recom.delete.diagnose.tip");
    public static final long MEDICATION_RECOM_EXPIRATION = ConfigUtil.getInt("prescription.expire.max") * 60 * 1000L;

    private List<MedicationBoxWithUsageVO> getRepeatDetail(Long doctorId, Long recommendId) throws BusinessException {
        List<MedicationBoxWithUsageVO> resultVO = new ArrayList<>();

        List<MedicationBoxVO> medicationBoxVOList = null;

        List<MedicationRecomDetailVO> recomDetailList = recomDetailService.getDetailsByRecomId(recommendId);
        // 构建 购药咨询数量 map<pid-quantity>
        List<Long> pidList = new ArrayList<>();
        Map<Long, MedicationRecomDetailVO> usageMap = new HashMap<>();
        if (null != recomDetailList && !recomDetailList.isEmpty()) {
            for (MedicationRecomDetailVO tempDetail : recomDetailList) {
                //pidList.add(tempDetail.getPid());
                pidList.add(tempDetail.getSkuId());
                usageMap.put(tempDetail.getPid(), tempDetail);
            }
        }

        // b2c接口获取药品详情 + 购买数量赋值
        if (null != pidList && !pidList.isEmpty()) {
            try {
                // 医生信息
                RecomUserInfoBO userInfo = remoter.getUserInfo(doctorId, null);
                RecomDoctorBO doctorInfo = userInfo.getDoctor();
                if (doctorInfo == null) {
                    throw new BusinessException(ExceptionCodes.DOCTOR_NOT_EXIST);
                }

                // 医生所在区域Id
                Integer cityId = doctorInfo.getPriceCityId();
                Integer clinic = doctorInfo.getClinic();
                Integer pfizer = doctorInfo.getPfizer() == null || !doctorInfo.getPfizer() ? 0 : 1;
                // 指数显示方式 :0不显示 、1小七指数、2市场积分
                Integer showCommission = doctorInfo.getShowCommission();
                medicationBoxVOList = remoter.getMedicationList(doctorId, cityId, pidList, false);
                // 处理控制指数显示方式:0不显示 、1小七指数、2市场积分
                medicationBoxVOList = generateShowCommission(medicationBoxVOList, showCommission);
            } catch (Exception e) {
                LOGGER.error("---------- getRepeatDetail ERROR ; build medication error : pidList={}", pidList.toString(), e);
            }

        }

        // b2c服务异常、网络异常等处理(用原推荐购药时信息)
        if (null == medicationBoxVOList || medicationBoxVOList.isEmpty()) {
            throw new BusinessException(ExceptionCodes.MEDICATION_PRODUCT_EXITS);
        }

        // 封装用法用量
        handleUsage(resultVO, medicationBoxVOList, usageMap);
        return resultVO;
    }

    /**
     * 处理续方用法用量详情 RecomServiceImpl.handleUsage()
     *
     * @param medicationBoxWithUsageVOList
     * @param medicationBoxVOList
     * @param usageMap
     * @Date 2017年12月19日
     * @since 2.14
     */
    private void handleUsage(List<MedicationBoxWithUsageVO> medicationBoxWithUsageVOList,
                             List<MedicationBoxVO> medicationBoxVOList,
                             Map<Long, MedicationRecomDetailVO> usageMap) {
        if (null != medicationBoxVOList && !medicationBoxVOList.isEmpty()) {
            MedicationBoxWithUsageVO medicationBoxWithUsageVO;
            MedicationRecomDetailVO medicationRecomDetailVO;
            for (MedicationBoxVO tempMedication : medicationBoxVOList) {
                medicationBoxWithUsageVO = new MedicationBoxWithUsageVO();
                BeanUtils.copyProperties(tempMedication, medicationBoxWithUsageVO);
                medicationRecomDetailVO = usageMap.get(tempMedication.getId());
                if (medicationRecomDetailVO == null) {
                    medicationBoxWithUsageVO.setQuantity(1);
                    continue;
                }
                Integer quantity = medicationRecomDetailVO.getQuantity();
                medicationBoxWithUsageVO.setQuantity(null == quantity ? 1 : quantity);
                medicationBoxWithUsageVO.setBackup(medicationRecomDetailVO.getBakup());
                // 设置用法用量明细
                Double dosageCycle = medicationRecomDetailVO.getDosageCycle();
                medicationBoxWithUsageVO.setDosageCycle(dosageCycle);
                medicationBoxWithUsageVO.setDosageCycleUnit(medicationRecomDetailVO.getDosageCycleUnit());
                medicationBoxWithUsageVO.setDosageCount(medicationRecomDetailVO.getDosageCount());
                medicationBoxWithUsageVO.setEachDosageCount(medicationRecomDetailVO.getEachDosageCount());
                medicationBoxWithUsageVO.setEachDoseUnit(medicationRecomDetailVO.getEachDoseUnit());
                medicationBoxWithUsageVO.setDrugCycle(medicationRecomDetailVO.getDrugCycle() != null
                    ? medicationRecomDetailVO.getDrugCycle().intValue() : null);
                medicationBoxWithUsageVO.setDrugCycleUnit(medicationRecomDetailVO.getDrugCycleUnit());
                //单位以药品列表中的为准
                medicationBoxWithUsageVO.setQuantityUnit(medicationRecomDetailVO.getQuantityUnit());
                medicationBoxWithUsageVO.setUsageMethod(medicationRecomDetailVO.getUsageMethod());
                medicationBoxWithUsageVO.setUsageTime(medicationRecomDetailVO.getUsageTime());
                medicationBoxWithUsageVO.setUsages(medicationRecomDetailVO.getUsages());
                boolean containUsageDetail = false;
                // 新版 每几日几次必填
                if (medicationRecomDetailVO.getDosageCycle() != null && medicationRecomDetailVO.getDosageCount() != null) {
                    containUsageDetail = true;
                }
                medicationBoxWithUsageVO.setContainUsageDetail(containUsageDetail);
                // 拼接字符串
                if (medicationRecomDetailVO.getDosageCycle() != null && medicationRecomDetailVO.getDosageCycleUnit() != null
                        && medicationRecomDetailVO.getDosageCount() != null) {
                    StringBuilder dStr = new StringBuilder();
                    if (!Constants.CYCLE_UNIT_TWO_DAY.equals(medicationRecomDetailVO.getDosageCycleUnit())) {
                        dStr.append(Constants.CYCLE_PREFIX);
                    }
                    if (!medicationRecomDetailVO.getDosageCycle().equals(1d)) {
                        dStr.append(RecomBizUtil.subZeroAndDot(medicationRecomDetailVO.getDosageCycle().toString()));
                    }
                    dStr.append(medicationRecomDetailVO.getDosageCycleUnit());
                    dStr.append(medicationRecomDetailVO.getDosageCount());
                    dStr.append(Constants.DOSAGE_COUNT_SUFFIX);
                    medicationBoxWithUsageVO.setDosageStr(dStr.toString());
                }
                medicationBoxWithUsageVOList.add(medicationBoxWithUsageVO);
            }
        }
    }

    /**
     * 设置指数显示方式 RecomServiceImpl.generateShowCommission()
     *
     * @param resultVO
     * @param showCommission
     * @return
     * @Author fangguanhong
     * @Date 2017年9月23日
     * @since 1.0.0
     */

    public List<MedicationBoxVO> generateShowCommission(List<MedicationBoxVO> resultVO, Integer showCommission) {
        if (null != resultVO && resultVO.size() > 0) {
            for (MedicationBoxVO medicationBox : resultVO) {
                medicationBox.setShowCommission(showCommission);
            }
        }
        return resultVO;
    }

    @Override
    public Integer getDrNumByDr(Long doctorId, Date start, Date end, Integer status) {
        return medicationRecomRepository.getDrNumByDr(doctorId, start, end, status);
    }


    @Override
    public MedicationRecomBO getRecomVO(Long recomId) {
        MedicationRecom recom = medicationRecomRepository.get(recomId);
        MedicationRecomBO recomVO = new MedicationRecomBO();
        if (null != recom) {
            BeanUtils.copyProperties(recom, recomVO);
            DrMedicationRecomInfo recomInfo = medicationRecomInfoRepository.findFirstByRecommendId(recomId);
            if (recomInfo != null) {
                recomVO.setDoctorName(recomInfo.getDoctorName());
            }
            setRewardAndMessageFlag(recom, recomVO);
        }
        return recomVO;
    }


    /**
     * 设置推荐概要 MedicationRecomServiceImpl.getRecomDetail()
     *
     * @param recomIds
     * @param liteVO
     * @Author guoyongxiang
     * @Date 2016年2月29日
     * @since 2.2.0
     */
    private void setRecomDetail(Set<Long> recomIds, List<DrMedicationRecomInfo> recoms, List<RecomLiteVO> liteVO,
                                boolean showPartBuy, Integer status) throws BusinessException {
        if (recomIds != null && recomIds.size() > 0) {
            List<MedicationRecomDetail> recomDetailList = medicationRecomDetailRepository.findByRecommendIdIn(recomIds);
            if (CollectionUtils.isEmpty(recomDetailList)) {
                return;
            }
            Map<Long, List<MedicationRecomDetail>> recomMap = new HashMap<>();
            recomDetailList.forEach(recomDetail -> {

                List<MedicationRecomDetail> recomDetails = recomMap
                        .computeIfAbsent(recomDetail.getRecommendId(), o -> new ArrayList<>());
                recomDetails.add(recomDetail);
            });
            for (DrMedicationRecomInfo recom : recoms) {
                List<RecomSkuVO> skus = new ArrayList<>();
                List<MedicationRecomDetail> recomDetails = recomMap.get(recom.getRecommendId());
                if (recomDetails != null && recomDetails.size() > 0) {
                    RecomSkuVO sku = new RecomSkuVO();
                    BeanUtils.copyProperties(recomDetails.get(0), sku);
                    if (sku.getBakup() == null) {
                        sku.setBakup("");
                    }
                    sku.setName(
                        (sku.getRecomName() == null ? sku.getName() : sku.getRecomName()).replaceAll("null", ""));
                    skus.add(sku);
                }
                // 是否已购,新加了状态，需要判断如果为1，则为已购买，其他情况为未购
                Integer buyStatus = null;
                //if (!showPartBuy) { //原处理逻辑
                //    buyStatus = this.getRecomBuyStatus(recom.getStatus(), showPartBuy);
                //} else {    //新处理逻辑：显示少购买、已取消、已作废处方——【医生端V3.4.0-by gongbaoqiang】
                //    buyStatus = this.getNewRecomBuyStatus(recom.getStatus(), recom.getInvalid());
                //}
                //recomVO.setStatusInfo(Constants.RecomStatusEunm.valuesOf(buyStatus).getInfo());
                liteVO.add(handleRecomVOInfo(recom, skus, buyStatus, status));
            }
        }
    }

    /**
     * 医生端优化1.1新增字段处理
     *
     * @param recom
     * @param skus
     */
    private RecomLiteVO handleRecomVOInfo(DrMedicationRecomInfo recom, List<RecomSkuVO> skus, Integer buyStatus, Integer status) throws BusinessException {
        RecomLiteVO recomVO = new RecomLiteVO(recom.getRecommendId(), recom.getPatientId(), recom.getCreatedAt(), buyStatus);
        Date now = new Date();
        recomVO.setName(recom.getPatientName());
        recomVO.setSkus(skus);
        recomVO.setDiagnosisDate(recom.getCreatedAt());
        //医生端优化1.1新增字段
        recomVO.setPatientName(recom.getPatientName());
        recomVO.setPatientGender(recom.getPatientGender());
        recomVO.setPatientAgeStr(recom.getPatientAgeStr());
        List<MedicationRecomDetail> recomDetails = this.medicationRecomDetailRepository.findByRecommendId(recom.getRecommendId());
        recomVO.setSkusSize(0);
        if (CollectionUtils.isNotEmpty(recomDetails)) {
            recomVO.setSkusSize(recomDetails.size());
        }
        MedicationRecom medicationRecom = medicationRecomRepository.get(recom.getRecommendId());
        recomVO.setDiagnosis(medicationRecom.getDiagnosis().replaceAll(",","、"));
        Integer recomSource = medicationRecom.getType() == MedicationRecom.RECOM_TYPE_REQUIRE
            ? MedicationRecomSourceTypeEnum.REQUIRE.getSourceType()
            : medicationRecom.getType() == MedicationRecom.RECOM_TYPE_MANNUL
                ? MedicationRecomSourceTypeEnum.TEXT.getSourceType()
                : MedicationRecomSourceTypeEnum.VIDEO.getSourceType();
        recomVO.setRecomSource(recomSource);
        RecomAuditLog auditLog = recomAuditLogRepository.findFirstByRecomId(recom.getRecommendId());
        if (null != status && !MedicationRecomInvalidStatusEnum.ALL.getType().equals(status)) {
            recomVO.setInvalidStatus(status);
            if (RecomAuditLog.AUDIT_STATUS_REJECT == auditLog.getStatus()) {
                recomVO.setRemark(auditLog.getRemark());
            }
        } else {
            if (MedicationRecom.RECOM_STATUS_NOT_BUY.equals(medicationRecom.getStatus()) && medicationRecom.getExpireAt().before(now)) {
                //超时未购买
                recomVO.setInvalidStatus(MedicationRecomInvalidStatusEnum.OVERTIME_NOT_PAY.getType());
            }
            if ((RecomAuditLog.AUDIT_STATUS_PENDING == auditLog.getStatus() && medicationRecom.getExpireAt().before(now)) || RecomAuditLog.AUDIT_STATUS_EXPIRED == auditLog.getStatus()) {
                //超时未审核
                recomVO.setInvalidStatus(MedicationRecomInvalidStatusEnum.OVERTIME_NOT_AUDIT.getType());
            }
            if (RecomAuditLog.AUDIT_STATUS_REJECT == auditLog.getStatus()) {
                //审核不通过
                recomVO.setInvalidStatus(MedicationRecomInvalidStatusEnum.AUDIT_NOT_PASS.getType());
                recomVO.setRemark(auditLog.getRemark());
            }
        }
        return recomVO;
    }

    /**
     * 处理新版用药记录状态问题
     *
     * @param status
     * @return
     */
    private int getNewRecomBuyStatus(Integer status, Integer invalid) {
        //状态为空或者已下单时，按已未购买处理
        if (status == null || status == Constants.RecomStatusEunm.ALREADY_ORDER.getCode()) {
            status = Constants.RecomStatusEunm.NOT_BUY.getCode();
        }
        if (invalid != null && invalid == MedicationRecom.INVALID_YES) {
            status = Constants.RecomStatusEunm.ALREADY_INVALID.getCode();
        }
        return status;
    }

    @Override
    public List<MedicationRecomBO> getSpecifydayRecom(List<Integer> recomStatus, Date start, Date end) {
        List<MedicationRecom> list = medicationRecomRepository.getTimeLimitRecom(start, end, recomStatus);
        // 如果该时间段内，某患者有多次推荐记录，则只取第一次的推荐记录
        Map<Long, Integer> recomPatientMap = new HashMap<>();
        List<MedicationRecomBO> voList = new ArrayList<>();
        if (CollUtil.isEmpty(list)) {
            return voList;
        }
        Set<Long> recomIds =
            list.stream().filter(m -> m.getStatus() == 2).map(MedicationRecom::getId).collect(Collectors.toSet());
        Map<Long, Long> orderIdMap = new HashMap<>();
        if (CollUtil.isNotEmpty(recomIds)) {
            orderIdMap = ib2cFeignClient.getOrderId(recomIds);
        }
        for (MedicationRecom medicationRecom : list) {
            Long patientId = medicationRecom.getPatientId();
            if (recomPatientMap.get(patientId) == null) {
                recomPatientMap.put(patientId, 1);
                MedicationRecomBO medicationRecomVO = new MedicationRecomBO();
                BeanUtil.copyProperties(medicationRecom, medicationRecomVO);
                if (medicationRecom.getStatus() == 2) {
                    medicationRecomVO.setOrderId(orderIdMap.get(medicationRecom.getId()) + "");
                }
                voList.add(medicationRecomVO);
            }
        }
        return voList;
    }


    @Override
    public Set<Long> getRecomDoctorInviter(Set<Long> recomIds) {
        // 获取推荐单列表对应的医生
        List<MedicationRecom> recomList = medicationRecomRepository.findByIdIn(recomIds);
        Set<Long> doctorIdSet = new HashSet<>();
        if (recomList != null && recomList.size() > 0) {
            for (MedicationRecom recom : recomList) {
                doctorIdSet.add(recom.getDoctorId());
            }
        }
        return doctorIdSet;
    }


    @Override
    public List<MedicationRecomBO> getMedicationRecomByIds(Set<Long> ids) {
        List<MedicationRecom> medicationRecom = medicationRecomRepository.findByIdIn(ids);
        return this.getMedicationRecoms(medicationRecom);
    }

    private List<MedicationRecomBO> getMedicationRecoms(List<MedicationRecom> medicationRecoms) {
        List<MedicationRecomBO> medicationRecomListVO = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(medicationRecoms)) {
            List<Long> recomIds = medicationRecoms.stream().map(MedicationRecom::getId).collect(Collectors.toList());
            List<DrMedicationRecomInfo> recomInfos = medicationRecomInfoRepository.findByRecommendIdIn(recomIds);
            Map<Long, DrMedicationRecomInfo> recomInfoMap = recomInfos.stream()
                    .collect(Collectors.toMap(DrMedicationRecomInfo::getRecommendId,
                            i -> i));

            medicationRecoms.stream().forEach(s -> {
                MedicationRecomBO bo = new MedicationRecomBO();
                DrMedicationRecomInfo recomInfo = recomInfoMap.get(s.getId());
                BeanUtil.copyProperties(s, bo);
                if (recomInfo != null) {
                    bo.setDoctorName(recomInfo.getDoctorName());
                }
                setRewardAndMessageFlag(s, bo);
                medicationRecomListVO.add(bo);
            });
        }
        return medicationRecomListVO;
    }

    @Override
    public List<MedicationRecomBO> getMedicationRecomByConsultSessionIds(Set<Long> consultSessionIds) {
        List<MedicationRecom> medicationRecom = medicationRecomRepository.findBySessionIdIn(consultSessionIds);
        return this.getMedicationRecoms(medicationRecom);
    }

    /**
     * 设置推荐病历数据收集是否奖励，是否发送通知 RecomServiceImpl.setRewardAndMessageFlag()
     *
     * @param recom
     * @param bo
     * @Author gongbaoqiang
     * @Date 2018年8月9日
     * @since 3.1.0
     */
    private void setRewardAndMessageFlag(MedicationRecom recom, MedicationRecomBO bo) {
        //病历数据收集状态为空时默认按同意收集计算，兼容老数据
        if (recom.getCollectStatus() == null || recom.getCollectStatus() == MedicationRecom.COLLECT_STATUS_AGREE) {
            bo.setRewardFlag(true);
            bo.setMessageFlag(true);
        } else if (recom.getCollectStatus() == MedicationRecom.COLLECT_STATUS_AGREE_NOT) {
            bo.setRewardFlag(false);
            bo.setMessageFlag(true);
        } else if (recom.getCollectStatus() == MedicationRecom.COLLECT_STATUS_NOT_TIPS) {
            bo.setRewardFlag(false);
            bo.setMessageFlag(false);
        }
    }


    @Override
    public PageVO<MedicationRecomPaBO> getRecomDrugList(Long patientId, Long doctorId, Long consultId, int page,
                                                        int num) {
        // 结果集
        List<MedicationRecomPaBO> recomVOs = new ArrayList<>();

        Page<MedicationRecom> recomPage = medicationRecomRepository
                .findByPatientIdAndDoctorIdAndSessionIdOrderByCreatedAtDesc(patientId,
                        doctorId,
                        consultId,
                        new PageParamVO(
                                page,
                                num)
                                .getPageable());

        return this.generateRecomPage(recomPage);
    }

    @Override
    public PageVO<MedicationRecomPaBO> getPatientRecomList(Long patientId, PageParamVO paramVO, Integer status, Integer type) {
        List<Integer> statusList = new ArrayList<>();
        Page<MedicationRecom> recomPage = null;
        if (null != status) {
            // 待购买(前端传递status=0)
            if (status.equals(MedicationRecom.RECOM_STATUS_NOT_BUY)) {
                statusList.add(MedicationRecom.RECOM_STATUS_NOT_BUY);
                recomPage = medicationRecomRepository
                        .findByPatientIdAndStatusInAndExpireAtAfterOrderByCreatedAtDesc(patientId, statusList, new Date(), paramVO.getPageable());
            } else {
                // 已购买(前端传递status=1)
                statusList.add(MedicationRecom.RECOM_STATUS_HAS_BUY);
                statusList.add(MedicationRecom.RECOM_STATUS_ORDERD);
                statusList.add(MedicationRecom.RECOM_STATUS_CANCEL);
                recomPage = medicationRecomRepository.findByPatientIdAndStatusInOrderByCreatedAtDesc(patientId, statusList, paramVO.getPageable());
            }
        } else {
            if (type != null) {
                log.info("续方申请：patientId:{} , status:{}, type:{}", patientId, status, type);
                statusList.add(MedicationRecom.RECOM_STATUS_HAS_BUY);
                statusList.add(MedicationRecom.RECOM_STATUS_ORDERD);
                statusList.add(MedicationRecom.RECOM_STATUS_CANCEL);
                //续方申请页面，去掉已经发送申请的
                recomPage = medicationRecomRepository.findByPatientIdAndLastRequireAtIsNullOrderByCreatedAtDesc(patientId, statusList, new Date(), paramVO.getPageable());
            } else {
                log.info("我的处方：patientId:{} , status:{}", patientId, status);
                //我的处方页面，显示全部
                recomPage = medicationRecomRepository.findByPatientIdOrderByCreatedAtDesc(patientId, paramVO.getPageable());

            }
        }
        return this.generateRecomPage(recomPage);
    }

    /**
     * 医生端1.1优化需求  失效处方
     *
     * @param doctorId
     * @param status
     * @param pageVO
     * @return
     */
    @Override
    public PageVO<RecomLiteVO> medicationInvalidList(Long doctorId, Integer status, PageParamVO pageVO) throws BusinessException {
        // 1.获取医生患者ID列表，以及名称对应关系
        Map<Long, PatientNameVO> patientNames = remoter.getPatientNames(doctorId, null);
        Page<DrMedicationRecomInfo> recomPage = null;
        if (MedicationRecomInvalidStatusEnum.AUDIT_NOT_PASS.getType().equals(status)) {
            //审核不通过
            recomPage = medicationRecomInfoRepository
                    .searchMedicationInvalidAuditNotPass(doctorId, status, pageVO.getPageable());
        } else if (MedicationRecomInvalidStatusEnum.OVERTIME_NOT_AUDIT.getType().equals(status)) {
            //超时未审核
            recomPage = medicationRecomInfoRepository
                    .searchMedicationInvalidAuditOvertime(doctorId, status, pageVO.getPageable());
        } else if (MedicationRecomInvalidStatusEnum.OVERTIME_NOT_PAY.getType().equals(status)) {
            //超时未购买
            recomPage = medicationRecomInfoRepository
                    .searchMedicationInvalidPayOvertime(doctorId, status, pageVO.getPageable());
        } else {
            //全部
            recomPage = medicationRecomInfoRepository
                    .searchMedicationInvalidList(doctorId, status, pageVO.getPageable());
        }
        // 3.转换推荐记录
        Set<Long> recomIds = new HashSet<>();
        Set<Long> patientIds = new HashSet<>();
        List<RecomLiteVO> liteVO = new ArrayList<>();
        for (DrMedicationRecomInfo recom : recomPage.getContent()) {
            recomIds.add(recom.getRecommendId());
            patientIds.add(recom.getPatientId());
        }
        // 4.转换推荐记录、设置推荐概要
        setRecomDetail(recomIds, recomPage.getContent(), liteVO, false, status);

        // 5.处理推荐列表患者昵称
        handleRecomLite(liteVO, patientNames);

        return PageVO.newBuilder()
                .pageNo(pageVO.getNum())
                .pageSize(pageVO.getPage())
                .totalCount((int) recomPage.getTotalElements())
                .result(liteVO)
                .build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer getRecommendTypeById(Long recomId) {
        if (recomId == null) {
            return 1;
        }
        MedicationRecom recom = medicationRecomRepository.findFirstById(recomId);
        return null == recom ? 1 : recom.getType();
    }

    private PageVO<MedicationRecomPaBO> generateRecomPage(Page<MedicationRecom> recomPage) {

        PageVO<MedicationRecom> pageVO = JpaPageConvertor.pageConvert(recomPage);
        // 结果集
        List<MedicationRecomPaBO> recomVOs = new ArrayList<>();
        // 推荐列表ids
        List<Long> recomIds = new ArrayList<>();
        for (MedicationRecom recom : recomPage.getContent()) {
            // 处理推荐id，统一查推荐明细备用
            recomIds.add(recom.getId());
            // 推荐VO
            MedicationRecomPaBO recomVO = new MedicationRecomPaBO();

            recomVO.setRecomTime(DateUtil.formatDate(recom.getCreatedAt(), DateUtil.DATE_TIME_FORMAT));
            recomVO.setPatientId(recom.getPatientId());
            recomVO.setDoctorId(recom.getDoctorId());
            recomVO.setRecomId(recom.getId());
            recomVO.setDiagnosis(recom.getDiagnosis());// 处方笺临床诊断
            recomVO.setStatus(recom.getStatus());
            recomVO.setExpire(recom.getExpireAt().after(new Date()) ? MedicationRecom.EXPIRE_NO : MedicationRecom.EXPIRE_YAEAH);
            recomVO.setInquirerId(recom.getInquirerId());
            recomVOs.add(recomVO);
        }

        if (recomIds.size() > 0) { // 有结果集，处理明细
            // 根据推荐id获取药品详情，每个推荐id的详情列表不会为null
            List<MedicationRecomDetail> recomDetailList = medicationRecomDetailRepository.findByRecommendIdIn(recomIds);
            Map<Long, List<MedicationRecomDetail>> recomItems = new HashMap<>();
            recomDetailList.forEach(recomDetail -> {
                List<MedicationRecomDetail> recomDetails = recomItems
                        .computeIfAbsent(recomDetail.getRecommendId(), o -> new ArrayList<>());
                recomDetails.add(recomDetail);
            });

            for (MedicationRecomPaBO recomVO : recomVOs) { // 处理推荐记录的药品信息
                // 药品列表
                List<MedicationRecomItemPaBO> items = new ArrayList<>();
                for (MedicationRecomDetail item : recomItems.get(recomVO.getRecomId())) {// 每个推荐都有详情list，没有数据为空数组，不会为null
                    MedicationRecomItemPaBO itemVO = new MedicationRecomItemPaBO();
                    BeanUtils.copyProperties(item, itemVO);
                    items.add(itemVO);
                }
                recomVO.setItems(items);
            }
        }

        if (recomPage.getTotalElements() == 0) {
            return new PageVO<>();
        }

        return PageVO.newBuilder()
                .pageNo(pageVO.getPageNo())
                .pageSize(pageVO.getPageSize())
                .totalCount(pageVO.getTotalCount())
                .offset(pageVO.getOffset())
                .result(recomVOs)
                .build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveRemarkName(Long doctorId, Long patientId, String patientName, Integer gender,
                                  Integer age, String ageUnit)
            throws BusinessException {
        if (doctorId == null || patientId == null || StringUtils.isBlank(patientName) || gender == null || age == null
                || StringUtils.isBlank(ageUnit)) {
            return false;
        }
        return remoter.saveRemarkName(doctorId, patientId, patientName, gender, age, ageUnit);
        // 医生对患者推荐用药次数
        // long examineCount = this.examineRecomDao.getExamineCount(doctorId, patientId);
        // long recomCount = this.medicationRecomDao.getRecomCount(doctorId, patientId);
        // 没有推荐过用药，则反写患者姓名
        // if (recomCount + examineCount <= 0) {
        // changed = this.remoter.saveRemarkName(doctorId, patientId, patientName);
        // }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveCrmRecomConfirm(Long recomId, Long pharmacistId, String pharmacistName, Long time, Integer status,
                                    String desc) throws BusinessException {

        MedicationRecom recom = medicationRecomRepository.findFirstById(recomId);
        DrMedicationRecomInfo recomInfo = medicationRecomInfoRepository.findFirstByRecommendId(recomId);
        if (null == recom || null == recomInfo) {
            throw new BusinessException(ExceptionCodes.DOCTOR_RECOM_EXITS);
        }
        if (DrMedicationRecomInfo.CHECKING_STATUS_IN != recomInfo.getCheckingStatus()) {
            throw new BusinessException(ExceptionCodes.DOCTOR_RECOM_NOT_NEED_AUDIT);
        }
        if (MedicationRecom.FORCE_RECOM_STATUS_NOT_SEND == recom.getForceRecom()) {
            throw new BusinessException(ExceptionCodes.DOCTOR_RECOM_WAIT_SEND);
        }
        if (status== DrMedicationRecomInfo.CHECKING_STATUS_PASS) {
            recom.setExpireAt(new Date(System.currentTimeMillis() + MEDICATION_RECOM_EXPIRATION));
            medicationRecomRepository.update(recom);
        }
        recomInfo.setCheckingStatus(status);
        recomInfo.setChangedAt(new Date(time));

        switch (status) {
            case DrMedicationRecomInfo.CHECKING_STATUS_NOT_PASS:
                String notPassDesc = StringUtils.isNotEmpty(desc) ? desc : "";
                recomInfo.setCheckingDesc(notPassDesc);
                break;
            case DrMedicationRecomInfo.CHECKING_STATUS_EXPIRED:
                //发送消息按审核未通过处理
                status = DrMedicationRecomInfo.CHECKING_STATUS_EXPIRED;
                recomInfo.setCheckingDesc(desc);
                break;
            case DrMedicationRecomInfo.CHECKING_STATUS_PASS:
                recomInfo.setCheckingDesc(DrMedicationRecomInfo.CHECKING_PASS_DESC);
                // 审核通过，医生已签名, 且药师电子签名开启,则更新药师签名状态、签名时间
                //if (recomInfo.getDoctorSignStatus() == DrMedicationRecomInfo.DOCTOR_SIGN_STATUS_DONE
                //        && recomInfo.getPharmacistSignConfig() == DrMedicationRecomInfo.PHARMACIST_SIGN_CONFIG_ON) {
                //    recomInfo.setPharmacistSignStatus(DrMedicationRecomInfo.PHARMACIST_SIGN_STATUS_DONE);
                recomInfo.setPharmacistId(pharmacistId);
                recomInfo.setPharmacistName(pharmacistName);
                if (null == recomInfo.getPharmacistSignTime()) {
                    recomInfo.setPharmacistSignTime(new Date(time));
                }
                //}

                /*
                 * 向患者发送短信提醒，
                 * 已作废的进行拦截【医生端V3.4.0-by gongbaoqiang  2018-10-18】
                 */
                //RecordHospitalDTO recordHospitalDTO = this.remoter.getRecordHospitalByDoctor(recom.getDoctorId());
                RecomUserInfoBO userDto = remoter.getUserInfo(recom.getDoctorId(), recom.getPatientId(), false);
//                log.info("进行一键续方提醒, type: {}, phone: {}, invalid: {}", recom.getType() == MedicationRecom.RECOM_TYPE_MANNUL,
//                        userDto.getPatient().getPhone() != null,
//                        recom.getInvalid() != MedicationRecom.INVALID_YES);
//                if (recom.getType() == MedicationRecom.RECOM_TYPE_REQUIRE && recom.getInvalid() != MedicationRecom.INVALID_YES) {
//                    patientFeignClient.publishMaMessage(MsgMaPublishParamBO.builder()
//                            .doctorId(recom.getDoctorId())
//                            .patientId(recom.getPatientId())
//                            .msgType(MsgMaPublishParamBO.MsgType.CONTINUED_PRESCRIPTION)
//                            .path("/pages/recipeDetail/recipeDetail?recomId=" + recomId + "&type=2")
//                            .content("【电子处方】")
//                            .build());
//                }
                if (recom.getType() == MedicationRecom.RECOM_TYPE_MANNUL
                        && userDto.getPatient().getPhone() != null
                        && recom.getInvalid() != MedicationRecom.INVALID_YES) {
                    SMSUtil.asyncSendSMS(userDto.getPatient().getPhone(), Template.RECOMMEND_REMIND_TO_PATIENT_TEMPLATE,
                            userDto.getDoctor().getHospitalName(), userDto.getDoctor().getDepartmentName(),
                            userDto.getDoctor().getName());
                }

                break;

            default:
                throw new BusinessException(ExceptionCodes.PARAM_ERROR);
        }

        medicationRecomInfoRepository.update(recomInfo);

        //对作废处方进行审核消息拦截
        if (recom.getInvalid() != MedicationRecom.INVALID_YES) {
            // 正常处方，走会话逻辑 视频的处方 不开会话
            // if (MedicationRecom.RECOM_TYPE_VIDEO != recom.getType()
            // && (recom.getRequireId() == null || recom.getRequireId() == 0L)) {
            IMRecomRemindDTO recomRemindDTO = new IMRecomRemindDTO();
            recomRemindDTO.setAuditDesc(desc);
            recomRemindDTO.setAuditResult(status);
            recomRemindDTO.setDoctorId(recom.getDoctorId());
            recomRemindDTO.setPatientId(recom.getPatientId());
            recomRemindDTO.setRecommendId(recomId);
            remoter.sendImRecomRemind(recomRemindDTO);

            // 异步同步处方数据到统计
            ThreadPoolUtil.execute(() -> {
                searchFeignClient.createRecipelRecordIndex(AsRecipelRecordBO.builder().doctorId(recom.getDoctorId())
                    .patientId(recom.getPatientId()).recipelId(recomId).recipelStatus(0)
                    .repeatStatus(recom.getOriginRecom() != null && recom.getOriginRecom() > 0 ? 1 : 0)
                    .generateDate(new Date()).createdAt(new Date()).createdBy("system").build());
            });

            // } else {
            // 处方审核不通过，不给患者发送消息
            if (DrMedicationRecomInfo.CHECKING_STATUS_NOT_PASS != status) {
                // 给患者发送订阅消息
                // patientFeignClient.publishMaMessage(MsgMaPublishParamBO.builder()
                // .doctorId(recom.getDoctorId())
                // .patientId(recom.getPatientId())
                // .msgType(recom.getType() == 2 ? MsgMaPublishParamBO.MsgType.CONTINUED_PRESCRIPTION :
                // MsgMaPublishParamBO.MsgType.RECOMMEND)
                // .path("/pages/recipeDetail/recipeDetail?recomId=" + recomId + "&type=2")
                // .content("【电子处方】")
                // .build());
                // LOGGER.info("药师审核求药处方，未走会话逻辑：recomId={}, requireId={}", recomId, recom.getRequireId());
                // List<MedicationRecomDetail> details = medicationRecomDetailRepository.findByRecommendId(recomId);
                // //续方处方不开启会话，直接给患者发送消息
                // recomMessageService.sendPtMessage(recomInfo.getDoctorId(), recomInfo.getPatientId(), recomId,
                // details);
            }

        }
        // 查询是否有病历
        MedicalRecordDoctorBO mrdBO = remoter.getDrCaseByRecomId(recom.getId());
        if (DrMedicationRecomInfo.CHECKING_STATUS_PASS == status) {
            if (mrdBO != null) {
                // 更新病历状态-2.19需求
                try {
                    remoter.updateRecord(mrdBO.getRecordId());
                } catch (Exception e) {
                    LOGGER.info("更新病历状态异常,message:{}", e.getMessage());
                    throw new BusinessException(ExceptionCodes.FAILED);
                }
            } else {
                // 异步请求保存诊疗记录 modified by guoping since 2.18 原先同步到搜索服务改为同步到病例服务
                MedicalRecordBO medicalRecordBO = recomCreaterService.buildSyncMedicalRecordBO(recomInfo, recom);
                LOGGER.info("处方审核同步到病例服务:medicalRecordBO={}", medicalRecordBO.toString());
                remoter.addPrescriptionRecord(medicalRecordBO);
            }
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateOrderRecom(RecomOrderInfoBO orderInfoBO) throws BusinessException {
        List<RecomInfoParamBO> recomInfoParams = orderInfoBO.getRecomInfo();
        if (CollectionUtils.isEmpty(recomInfoParams) && orderInfoBO.getBuyStatus() != RecomOrderInfoBO.BUY_STATUS_ALL) {
            LOGGER.error("订单回调同步推荐状态失败，推荐信息为空：orderInfoBO=" + orderInfoBO.toString());
            throw new BusinessException(ExceptionCodes.PARAM_ERROR);
        }
        Integer buyStatus = orderInfoBO.getBuyStatus();
        if (buyStatus == null) {
            LOGGER.error("订单回调同步推荐状态失败，推荐购买状态为空：orderInfoBO=" + orderInfoBO.toString());
            throw new BusinessException(ExceptionCodes.PARAM_ERROR);
        }

        int recomStatus = buyStatus;
        if (buyStatus == RecomStatusEunm.ALREADY_CANCEL.getCode()) {
            // 取消的订单直接将处方重置到未购买状态
            log.info("订单取消，重置处方状态到未购买，处方信息 {}", JsonMapper.toJson(orderInfoBO));
            recomStatus = RecomStatusEunm.NOT_BUY.getCode();
        }

        // 推荐ID(参数有重复)
        Set<Long> recomIdSet = recomInfoParams.stream().map(RecomInfoParamBO::getRecommendId).collect(Collectors.toSet());
        medicationRecomRepository.updateRecomStatus(recomStatus, recomIdSet);

        //已下单未支付调用不发送通知
        if (buyStatus == Constants.RecomStatusEunm.ALREADY_ORDER.getCode()) {
            return;
        }
        List<DrMedicationRecomInfo> recomInfoList = medicationRecomInfoRepository.findByRecommendIdIn(recomIdSet);
        RecomBuyNotifyParamBO notifyParamBO = new RecomBuyNotifyParamBO();
        List<RecomInfoParamBO> paramList = new ArrayList<>();
        RecomInfoParamBO recomInfoBO;
        for (DrMedicationRecomInfo recomInfo : recomInfoList) {
            recomInfoBO = new RecomInfoParamBO();
            recomInfoBO.setDoctorId(recomInfo.getDoctorId());
            recomInfoBO.setPatientName(recomInfo.getPatientName());
            recomInfoBO.setRecommendId(recomInfo.getRecommendId());

            //非阳光化医生不发送已购买和已取消通知，少购买通知不做拦截——【医生端V3.4.0-by gongbaoqiang  2018-10-18】
            if (buyStatus == Constants.RecomStatusEunm.ALREADY_BUY.getCode()
                    || buyStatus == Constants.RecomStatusEunm.ALREADY_CANCEL
                    .getCode()) {
                continue;
            }
            //判断是那种类型消息：少购买、已购买、已取消
            if (buyStatus == Constants.RecomStatusEunm.ALREADY_BUY.getCode()) {
                recomInfoBO.setType(RecomInfoParamBO.TEMPLATE_TYPE_RECOMMEND_ALLBUY);   //全购买
            } else if (buyStatus == Constants.RecomStatusEunm.PART_BUY.getCode()) {
                recomInfoBO.setType(RecomInfoParamBO.TEMPLATE_TYPE_RECOMMEND_PARTBUY);  //少购买
            } else if (buyStatus == Constants.RecomStatusEunm.ALREADY_CANCEL.getCode()) {
                recomInfoBO.setType(RecomInfoParamBO.TEMPLATE_TYPE_RECOMMEND_CANCELBUY);  //已取消
            }
            paramList.add(recomInfoBO);
        }
        if (CollectionUtils.isNotEmpty(paramList)) {
            notifyParamBO.setRecomInfoList(paramList);
            LOGGER.info("发送购买通知：notifyParamBO=" + notifyParamBO.toString());
            remoter.sendRecomPartBuyNotify(notifyParamBO);
        }
    }


    @Override
    public List<DrPointPrescriptionBO> getPrescriptionList(Long orderId, Long doctorId, String recomIds) {
        List<DrPointPrescriptionBO> list = new ArrayList<>();

        Set<Long> recommendIds = StringUtil.convertLongStr2Set(recomIds, ",");
        // 推荐单信息
        List<MedicationRecom> recomList = medicationRecomRepository.findByIdIn(recommendIds);
        if (recomList == null || recomList.isEmpty()) {
            LOGGER.warn("推荐单信息为空，recommendIds：{}, orderId={}, doctorId={}", recommendIds, orderId, doctorId);
            return list;
        }

        // 推荐单详情
        List<MedicationRecomDetail> recomDetailLists = medicationRecomDetailRepository.findByRecommendIdIn(recommendIds);
        Map<Long, List<MedicationRecomDetail>> recomDetailsMap = new HashMap<>();
        recomDetailLists.forEach(recomDetail -> {
            List<MedicationRecomDetail> recomDetails = recomDetailsMap
                    .computeIfAbsent(recomDetail.getRecommendId(), o -> new ArrayList<>());
            recomDetails.add(recomDetail);
        });

        for (MedicationRecom medicationRecom : recomList) {
            DrPointPrescriptionBO prescription = new DrPointPrescriptionBO();
            Long recommendId = medicationRecom.getId();
            prescription.setRecomId(recommendId);
            prescription.setSerialNumber(medicationRecom.getSerialNumber());
            prescription.setDiagnosis(medicationRecom.getDiagnosis());
            // 处方笺药品列表
            List<MedicationRecomDetail> recomDetailList = recomDetailsMap.get(recommendId);
            List<MedicationRecomItemBO> items = handleRecomItems(recomDetailList);
            prescription.setItems(items);
            list.add(prescription);
        }

        return list;
    }

    /**
     * 推荐单详情 RecomServiceImpl.handleRecomItems()
     *
     * @param recomDetailList
     * @return
     * @Author wangchuan
     * @Date 2017年12月19日
     * @since 2.14.0
     */
    private List<MedicationRecomItemBO> handleRecomItems(List<MedicationRecomDetail> recomDetailList) {
        List<MedicationRecomItemBO> items = new ArrayList<>();
        if (recomDetailList == null || recomDetailList.isEmpty()) {
            return items;
        }

        for (MedicationRecomDetail recomDetail : recomDetailList) {
            MedicationRecomItemBO item = new MedicationRecomItemBO();
            item.setPid(recomDetail.getPid());
            item.setSkuId(recomDetail.getSkuId());
            item.setName(recomDetail.getName());
            item.setCommonName(recomDetail.getCommonName());
            item.setQuantity(recomDetail.getQuantity());
            item.setUsages(recomDetail.getUsages());
            item.setBackup(recomDetail.getBakup());
            items.add(item);
        }

        return items;
    }

    @Override
    public PageVO<RecomLiteVO> getRecomSearchPage(Long doctorId, String key, PageParamVO pageVO, boolean showPartBuy)
            throws BusinessException {

        // 1.获取医生患者ID列表，以及名称对应关系
        Map<Long, PatientNameVO> patientNames = remoter.getPatientNames(doctorId, null);
        //
        //        if (MapUtils.isEmpty(patientNames)) {
        //            LOGGER.error("[查询推荐记录] getRecomSearchPage info ; 医生对应患者信息获取为空 : doctorId={},key={},pageVO={}", doctorId, key, pageVO);
        //            return new PageVO<>();
        //        }
        //        // 2.查询推荐记录
        //        Set<Long> patientIdSet = patientNames.keySet();
        //        Page<MedicationRecom> recomPage = medicationRecomRepository
        //                .findByDoctorIdAndPatientIdInAndTypeNotAndForceRecomNotOrderByCreatedAtDesc(doctorId, patientIdSet,
        //                                                                                            MedicationRecom.RECOM_TYPE_SYSTEM,
        //                                                                                            MedicationRecom.FORCE_RECOM_STATUS_NOT_SEND,
        //                                                                                            pageVO.getPageable());
        Page<DrMedicationRecomInfo> recomPage = null;
        if (StringUtils.isNotBlank(key)) {
            recomPage = medicationRecomInfoRepository
                    .searchByDoctorIdAndPatientName(doctorId, "%" + key + "%", pageVO.getPageable());
        } else {
            recomPage = medicationRecomInfoRepository.searchByDoctorId(doctorId, pageVO.getPageable());
        }
        // 3.转换推荐记录
        Set<Long> recomIds = new HashSet<>();
        Set<Long> patientIds = new HashSet<>();
        List<RecomLiteVO> liteVO = new ArrayList<>();
        for (DrMedicationRecomInfo recom : recomPage.getContent()) {
            recomIds.add(recom.getRecommendId());
            patientIds.add(recom.getPatientId());
        }
        // 4.转换推荐记录、设置推荐概要
        setRecomDetail(recomIds, recomPage.getContent(), liteVO, showPartBuy, MedicationRecomInvalidStatusEnum.ALL.getType());

        // 5.处理推荐列表患者昵称
        handleRecomLite(liteVO, patientNames);
        return PageVO.newBuilder()
                .pageNo(pageVO.getNum())
                .pageSize(pageVO.getPage())
                .totalCount((int) recomPage.getTotalElements())
                .result(liteVO)
                .build();
    }

    /**
     * 处理推荐列表患者昵称 MedicationRecomServiceImpl.handleRecomLite()
     *
     * @param recoms
     * @param paNameMap
     * @Author guoyongxiang
     * @Date 2016年3月1日
     * @since 2.2.0
     */
    private void handleRecomLite(List<RecomLiteVO> recoms, Map<Long, PatientNameVO> paNameMap) {
        for (RecomLiteVO recom : recoms) {
            PatientNameVO paNameVO = paNameMap.get(recom.getPatientId());
            // 如果患者姓名为空则取昵称
            String remarkName = "";
            String headUrl = "";
            String name = "";
            if (paNameVO != null) {
                remarkName = paNameVO.getRemarkName();
                headUrl = paNameVO.getHeadUrl();
                if (headUrl.startsWith("http:")) {
                    headUrl = headUrl.replaceAll("http:","https:");
                }
                name = paNameVO.getName();
            }
            recom.setRemarkName(remarkName);
            recom.setHeadUrl(headUrl);
            recom.setName(name);
        }
    }


    @Override
    public RecomDetailVO getRecomSearchDetail(Long recomId, Long doctorId, boolean showPartBuy) throws BusinessException {

        RecomDetailVO detailVO = new RecomDetailVO();

        MedicationRecom recom = medicationRecomRepository.get(recomId);
        DrMedicationRecomInfo recomInfo = medicationRecomInfoRepository.findFirstByRecommendId(recomId);
        if (recom == null) {
            LOGGER.warn("[获取用药记录详情] getRecomSearchDetail error ; 推荐ID不存在ID : recomId={}", recomId);
            throw new BusinessException(ExceptionCodes.DOCTOR_RECOM_EXITS);
        }

        RecomUserInfoBO userInfo = remoter.getUserInfo(recom.getDoctorId(), recom.getPatientId(), true);
        if (null == userInfo || null == userInfo.getDoctor() || null == userInfo.getPatient()) {
            LOGGER.warn("[获取用药记录详情] getRecomSearchDetail error ; 用户信息异常 : recomId={},doctorId={},patientId={}", recomId,
                    recom.getDoctorId(),
                    recom.getPatientId());
            throw new BusinessException(ExceptionCodes.DOCTOR_RECOM_EXITS);
        }
        RecomDoctorBO doctorDTO = userInfo.getDoctor();
        RecomPatientBO patientDTO = userInfo.getPatient();
        // 这里要先校验医患关系
        String doctorPatientRelationRedisKey = DoctorPatientRelation.getRedisKey(doctorId, recom.getPatientId());
        Object doctorPatientRelation = RedisUtil.valueOps().getObject(doctorPatientRelationRedisKey);
        if (doctorPatientRelation != null && doctorPatientRelation.equals(DoctorPatientRelation.RELATION_FLAG_DELETE)) {
            throw new BusinessException(ExceptionCodes.PATIENT_RELATION_DELETE);
        }
        // 构建sku信息
        List<RecomSkuVO> skuList = new ArrayList<>();
        int totalSalePrice = buildSkuInfo(recomId, recom, doctorDTO, skuList, showPartBuy);

        // 推荐用户信息V2.9版本前后用户数据兼容
        Integer patientAge;
        String patientGenderStr;
        String patientName;
        String patientAgeUnit;
        if (null != recomInfo) {
            patientAge = recomInfo.getPatientAge();
            patientGenderStr = patientDTO.getGenderStr(recomInfo.getPatientGender());
            patientName = recomInfo.getPatientName();
            patientAgeUnit = StringUtils.isNotEmpty(recomInfo.getPatientAgeUnit()) ? recomInfo.getPatientAgeUnit()
                    : AgeUnitEunm.YEAR.getUnit();
        } else {
            patientAge = patientDTO.getAge();
            patientGenderStr = patientDTO.getGenderStr();
            patientName = patientDTO.getName();
            patientAgeUnit = patientAge != null ? AgeUnitEunm.YEAR.getUnit() : "";
        }

        String selfAge = patientDTO.getAge() != null ? patientDTO.getAge() + AgeUnitEunm.YEAR.getUnit() : "";
        String selfGenderStr = patientDTO.getGenderStr();
        String selfName = patientDTO.getName();

        detailVO.setSelfName(selfName);
        detailVO.setSelfAge(selfAge);
        detailVO.setSelfGender(selfGenderStr);
        detailVO.setAge(patientAge);
        detailVO.setPatientAgeUnit(patientAgeUnit);
        detailVO.setPatientAgeStr(recomInfo.getPatientAgeStr());
        detailVO.setGender(patientGenderStr);
        detailVO.setPatientName(patientName);
        detailVO.setHeadUrl(patientDTO.getHeadUrl());
        detailVO.setPatientId(recom.getPatientId());
        //todo:当前取时的固化价格，需要调整为按购买区分：已购买取下单价格，未购买取实时价格
        detailVO.setTotalSalePrice(totalSalePrice);
        detailVO.setCreatedAt(recom.getCreatedAt());
        detailVO.setSkus(skuList);
        //新处理逻辑：显示少购买、已取消、已作废处方——【医生端V3.4.0-by gongbaoqiang】
        Integer buyStatus = getNewRecomBuyStatus(recom.getStatus(), recom.getInvalid());
        detailVO.setStatus(buyStatus);
        detailVO.setStatusInfo(Constants.RecomStatusEunm.valuesOf(buyStatus).getInfo());
        return detailVO;
    }

    private int buildSkuInfo(Long recomId, MedicationRecom recom, RecomDoctorBO doctorDTO, List<RecomSkuVO> skuList,
                             boolean showPartBuy) {
        // 查询未购买商品列表
        List<MedicationRecomDetail> detailList = medicationRecomDetailRepository.findByRecommendId(recomId);

        int totalSalePrice = 0;
        for (MedicationRecomDetail detail : detailList) {
            RecomSkuVO skuVO = new RecomSkuVO();
            BeanUtils.copyProperties(detail, skuVO);
            if (skuVO.getBakup() == null) {
                skuVO.setBakup("");
            }

            String commissionStr = "";
            String marketPoint = "";
            int salePrice = detail.getSalePrice() == null ? 0 : detail.getSalePrice();
            totalSalePrice += salePrice * detail.getQuantity();
            skuVO.setSalePrice(salePrice);
            skuVO.setDrCommission(commissionStr);
            skuVO.setMarketPoint(marketPoint);
            skuList.add(skuVO);
        }
        return totalSalePrice;
    }

    @Override
    @Transactional
    public MedicationPrescriptionVO getRepeatPrescription(Long doctorId, Long recommendId) throws BusinessException {
        MedicationRequire require = medicationRequireRepository.findFirstByFormerRecommendId(recommendId);
        if (require == null) {
            throw new BusinessException(ExceptionCodes.REQUIRE_RECORD_NOT_EXIST);
        }
        if (require.getApplyStatus() != MedicationRequire.APPLY_STATUS_DEFAULT) {
            throw new BusinessException(ExceptionCodes.REQUIRE_ALREADY_HANDLE);
        }
        return buildRequireRecomInfo(doctorId,recommendId);
    }

    private MedicationPrescriptionVO buildRequireRecomInfo(Long doctorId, Long recommendId) throws BusinessException {
        // 获取推荐药品信息
        MedicationPrescriptionVO medicationPrescription = new MedicationPrescriptionVO();
                // 根据推荐单ID查询推荐单基本信息 change by linhf 2017-06-08
        MedicationRecom medicationRecomVO = medicationRecomRepository.get(recommendId);
        Long inquirerId = medicationRecomVO.getInquirerId();

        List<MedicationBoxWithUsageVO> repeatDetails = getRepeatDetail(doctorId, recommendId);

        medicationPrescription.setMedicationList(repeatDetails);
        // 获取诊断信息
        List<DrMedicationRecomDiagnosis> recomDiagnosisList = medicationRecomDiagnosisRepository
                .findByRecommendId(recommendId);
        List<String> diagnosisList = new ArrayList<>();
        StringBuilder diagnosisBuffer = new StringBuilder();
        if (CollectionUtils.isNotEmpty(recomDiagnosisList)) {
            String diagnosisStr;
            for (DrMedicationRecomDiagnosis tempDiagnosis : recomDiagnosisList) {
                diagnosisBuffer.append(",");
                diagnosisStr = tempDiagnosis.getName();
                diagnosisBuffer.append(diagnosisStr);
                diagnosisList.add(diagnosisStr);
            }
        }

        //医生端3.5  灰度诊断医生删除非标准诊断  2018-11-20 王林
        //处理续方中非标准诊断问题
        handleDiagnosis(doctorId, recommendId, diagnosisList, diagnosisBuffer, medicationPrescription);

        String diagnoseShow = diagnosisBuffer.toString();
        if (diagnoseShow.length() > 0) {
            diagnoseShow = diagnoseShow.substring(1);
        }
        medicationPrescription.setDiagnoseShow(diagnoseShow);
        medicationPrescription.setDiagnosis(diagnosisList);
        // 处理续方初始价格
        handleRepeatPrice(medicationPrescription);
        medicationPrescription.setInquirerId(inquirerId);
        return medicationPrescription;
    }

    /**
     * 获取医生主动续方处方信息
     * @param doctorId
     * @param recommendId
     * @return
     * @throws BusinessException
     */
    @Override
    public MedicationPrescriptionVO getDrRepeatPrescriptionDetail(Long doctorId, Long recommendId) throws BusinessException {
        return buildRequireRecomInfo(doctorId,recommendId);
    }

    /**
     * 处理续方中非标准诊断问题 RecomServiceImpl.handleRepeatPrice()
     *
     * @param medicationPrescription
     * @since 3.5
     */
    private void handleDiagnosis(Long doctorId, Long recommendId, List<String> diagnosisList,
                                 StringBuilder diagnosisBuffer,
                                 MedicationPrescriptionVO medicationPrescription) throws BusinessException {
        RecomUserInfoBO userInfo = remoter.getUserInfo(doctorId, null, true);
        if (null == userInfo || null == userInfo.getDoctor()) {
            LOGGER.warn("[续方详情] repeat error ; 用户信息异常 : recommendId={},doctorId={}", recommendId, doctorId);
            throw new BusinessException(ExceptionCodes.DOCTOR_RECOM_EXITS);
        }
        RecomDoctorBO doctorBO = userInfo.getDoctor();
        //表示医生是灰度诊断医生
        if (doctorBO.getLabel() != null && doctorBO.getLabel().getDiagnosis()) {
            if (CollectionUtils.isNotEmpty(diagnosisList)) {
                List<DrStandardDiagnosis> drStandardDiagnoses = drStandardDiagnosisRepository.findByNameIn(diagnosisList);

                if (CollectionUtils.isNotEmpty(drStandardDiagnoses)) {
                    if (drStandardDiagnoses.size() != diagnosisList.size()) {
                        diagnosisList.clear();
                        diagnosisBuffer.setLength(0);
                        medicationPrescription.setDiagnoseDeleteTip(RECOM_DELETE_DIAGNOSE_TIP);
                        String diagnosisStr;
                        for (DrStandardDiagnosis tempDiagnosis : drStandardDiagnoses) {
                            diagnosisStr = tempDiagnosis.getName();
                            diagnosisBuffer.append("," + diagnosisStr);
                            diagnosisList.add(diagnosisStr);
                        }
                    }
                } else {
                    diagnosisList.clear();
                    diagnosisBuffer.setLength(0);
                    medicationPrescription.setDiagnoseDeleteTip(RECOM_DELETE_DIAGNOSE_TIP);
                }
            }
        }
    }

    /**
     * 处理续方价格信息 RecomServiceImpl.handleRepeatPrice()
     *
     * @param medicationPrescription
     * @Date 2017年12月19日
     * @since 2.14
     */
    private void handleRepeatPrice(MedicationPrescriptionVO medicationPrescription) {
        DecimalFormat decimalFormat = new DecimalFormat("##0.00");
        List<MedicationBoxWithUsageVO> medicationVOList = medicationPrescription.getMedicationList();
        BigDecimal totalPriceDecimal = BigDecimal.ZERO;
        BigDecimal priceDecimal;
        BigDecimal countDecimal;
        for (MedicationBoxWithUsageVO medicationBoxWithUsageVO : medicationVOList) {
            String priceStr = medicationBoxWithUsageVO.getSalePrice();
            if (StringUtils.isNotEmpty(priceStr)) {
                priceDecimal = new BigDecimal(priceStr);
                countDecimal = new BigDecimal(medicationBoxWithUsageVO.getQuantity());
                //销售价格由分换算成元（2021-05-19 by mh 不用乘以数量，手机端自己计算）
                medicationBoxWithUsageVO.setSalePrice(decimalFormat.format(priceDecimal.divide(new BigDecimal(100))));
                priceDecimal = priceDecimal.multiply(countDecimal);
                totalPriceDecimal = totalPriceDecimal.add(priceDecimal);
            }
        }
        medicationPrescription.setTotalPrice(totalPriceDecimal.intValue());
    }

    /**
     * 删除续方
     *
     * @param doctorId
     * @param recommendId
     * @throws BusinessException
     * @Date 2017年12月21日
     * @see IRecomService#deleteRecom(java.lang.Long, java.lang.Long)
     * @since 2.14
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRecom(Long doctorId, Long recommendId) throws BusinessException {
        MedicationRecom medicationRecom = medicationRecomRepository.get(recommendId);
        if (medicationRecom == null || medicationRecom.getDoctorId().longValue() != doctorId) {
            throw new BusinessException(ExceptionCodes.RECOM_NOT_EXIST);
        }
        medicationRecom.setVisiable(Constants.STATUS_YES.byteValue());
        medicationRecom.setChangedAt(new Date());
        medicationRecomRepository.update(medicationRecom);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RecomRecordVO getDoctorRecord(Long doctorId) throws BusinessException {
        RecomRecordVO recomRecordVO = new RecomRecordVO();
        DrRecordAuthorityBO drRecordBO = remoter.getRecordInfoByDoctorId(doctorId);
        if (drRecordBO == null) {
            recomRecordVO.setForbidenRecom(Constants.FORBIDEN_STATUS_NULL);
        } else {
            // 是否可推荐处方:0:历史数据， 1：允许，2：禁止
            recomRecordVO.setForbidenRecom(drRecordBO.getRecommandDrug());
            recomRecordVO.setRemindInfo(drRecordBO.getRemindInfo());
        }
        return recomRecordVO;
    }

    @Override
    public DrBaseBusinessDataBO getDrBaseBusinessData(Long doctorId) {
        String businessData = RedisUtil.valueOps().getString(getDrBaseBusinessDataKey(doctorId));
        // 累计处理求药数
        Integer requireRecomNum = medicationRequireRepository.countByDoctorIdAndApplyStatusIn(doctorId, Arrays.asList(
                MedicationRequire.APPLY_STATUS_REPEAT,
                MedicationRequire.APPLY_STATUS_SUSPEND));
        // 待处理求药数
        Integer untreatedRequireNum = medicationRequireRepository.countByDoctorIdAndApplyStatusIn(doctorId, Arrays.asList(
                MedicationRequire.APPLY_STATUS_DEFAULT));
        // 审核通过数量(包含自动审核数量)
        //Integer auditSuccessNum = medicationRecomInfoRepository.countByDoctorIdAndCheckingStatus(doctorId,
        //        DrMedicationRecomInfo.RECOMMAND_CHECKING_STATUS_PASS);
        Integer auditSuccessNum = medicationRecomInfoRepository.countByDoctorIdAndCheckingStatusIn(doctorId,
                Arrays.asList(
                        new Integer[]{DrMedicationRecomInfo.RECOMMAND_CHECKING_STATUS_PASS,
                                DrMedicationRecomInfo.RECOMMAND_CHECKING_STATUS_NO_CHECK}));
        if (StringUtils.isNotBlank(businessData)) {
            // 直接返回
            return DrBaseBusinessDataBO.builder()
                    .recomAuditRate(businessData)
                    .requireRecomNum(requireRecomNum)
                    .untreatedRequireNum(untreatedRequireNum)
                    .medicationRecomNum(auditSuccessNum)
                    .build();
        }

        // 审核不通过数量
        Integer auditFailNum = medicationRecomInfoRepository.countByDoctorIdAndCheckingStatus(doctorId,
                DrMedicationRecomInfo.RECOMMAND_CHECKING_STATUS_NOT_PASS);
        // 处方审核通过率
        businessData = 0 == auditSuccessNum || 0 == (auditFailNum + auditSuccessNum) ? "0.0" : new DecimalFormat(
                "0.0").format(BigDecimal.valueOf(auditSuccessNum)
                .divide(BigDecimal.valueOf((auditSuccessNum + auditFailNum)), 3, BigDecimal.ROUND_HALF_UP)
                .multiply(BigDecimal.valueOf(100)));
        businessData += "%";
        // 存放缓存，有效期10分钟
        RedisUtil.valueOps().set(getDrBaseBusinessDataKey(doctorId), businessData, 10 * 60);
        return DrBaseBusinessDataBO.builder()
                .recomAuditRate(businessData)
                .requireRecomNum(requireRecomNum)
                .untreatedRequireNum(untreatedRequireNum)
                .medicationRecomNum(auditSuccessNum)
                .build();
    }

    private String getDrBaseBusinessDataKey(Long doctorId) {
        return CommonConstant.REDIS_PRE_DR + "base_business_data_" + doctorId;
    }

    @Override
    public List<RecomPrescriptionBO> recomPrescriptionList(List<Long> recomIds) {
        List<MedicationRecom> medicationRecomList = medicationRecomRepository.findByIdIn(recomIds);
        if (CollectionUtils.isEmpty(medicationRecomList)) {
            return null;
        }
        List<RecomPrescription> recomPrescriptions = recomPrescriptionRepository.findByRecommendIdIn(recomIds);
        recomPrescriptions = recomPrescriptions.stream().sorted(Comparator.comparing(RecomPrescription::getType))
            .collect(Collectors.toList());
        Map<Long, RecomPrescription> recomPrescriptionMap = recomPrescriptions.stream()
            .collect(Collectors.toMap(RecomPrescription::getRecommendId, Function.identity(), (a, b) -> b));

        return medicationRecomList.stream().filter(recom -> recomPrescriptionMap.get(recom.getId()) != null)
            .map(recom -> RecomPrescriptionBO.builder().recomId(recom.getId()).serialNumber(recom.getSerialNumber())
                .pdfUrl(recomPrescriptionMap.get(recom.getId()).getPrescriptionPhotoUrl()).build())
            .collect(Collectors.toList());
    }

    @Override
    public Map<Long, Integer> getRecomStatusMap(Set<Long> recomIds) {
        List<MedicationRecom> medicationRecomList = medicationRecomRepository.findByIdIn(recomIds);
        if (CollectionUtils.isEmpty(medicationRecomList)) {
            return null;
        }
        return medicationRecomList.stream()
            .collect(Collectors.toMap(MedicationRecom::getId, MedicationRecom::getStatus, (a, b) -> b));
    }

    /**
     * 医生端患者续方记录
     * @param doctorId
     * @param inquirerId
     * @param pageVO
     * @return
     */
    @Override
    public PageVO<DrRequireListVO> getRequireRecomSearchPage(Long doctorId, Long inquirerId, PageParamVO pageVO) throws BusinessException{
        // 1.获取医生患者ID列表，以及名称对应关系
        Page<DrMedicationRecomInfo> recomPage = medicationRecomInfoRepository
                    .searchByDoctorIdAndInquirerIdAndCheckingStatus(doctorId, inquirerId, pageVO.getPageable());
        Set<Long> recomIds = new HashSet<>();
        List<DrRequireListVO> liteVOs = new ArrayList<>();
        for (DrMedicationRecomInfo recom : recomPage.getContent()) {
            recomIds.add(recom.getRecommendId());
        }

        //诊断信息
        List<MedicationRecom> recoms = medicationRecomRepository.findByIdIn(recomIds);
        Map<Long,String> diagnosisMap = recoms.stream().collect(Collectors.toMap(MedicationRecom::getId,MedicationRecom::getDiagnosis));

        List<MedicationRecomDetail> recomDetailList = medicationRecomDetailRepository.findByRecommendIdIn(recomIds);
        Map<Long, List<MedicationRecomDetail>> recomMap = new HashMap<>();
        recomDetailList.forEach(recomDetail -> {
            List<MedicationRecomDetail> recomDetails = recomMap
                    .computeIfAbsent(recomDetail.getRecommendId(), o -> new ArrayList<>());
            recomDetails.add(recomDetail);
        });
        for (DrMedicationRecomInfo recom : recomPage.getContent()) {
            List<DrRequireSkuListVO> skus = new ArrayList<>();
            List<MedicationRecomDetail> recomDetails = recomMap.get(recom.getRecommendId());
            if (recomDetails != null && recomDetails.size() > 0) {
                skus = recomDetails.stream().map(r->{
                    DrRequireSkuListVO sku = new DrRequireSkuListVO();
                    sku.setName(r.getName());
                    sku.setQuantity(r.getQuantity());
                    sku.setQuantityUnit(r.getQuantityUnit());
                    return sku;
                }).collect(Collectors.toList());
            }
            DrRequireListVO liteVO = new DrRequireListVO();
            liteVO.setId(recom.getRecommendId());
            liteVO.setPatientId(recom.getPatientId());
            liteVO.setCreatedAt(recom.getCreatedAt());
            liteVO.setPatientGender(recom.getPatientGender());
            liteVO.setPatientName(recom.getPatientName());
            liteVO.setSkus(skus);
            liteVO.setDiagnosis(diagnosisMap.get(recom.getRecommendId())!=null?diagnosisMap.get(recom.getRecommendId()).replaceAll(",","、"):"");
            liteVOs.add(liteVO);
        }
        return PageVO.newBuilder()
                .pageNo(pageVO.getNum())
                .pageSize(pageVO.getPage())
                .totalCount((int) recomPage.getTotalElements())
                .result(liteVOs)
                .build();
    }

    @Override
    public PrescriptionPlatformRecomInfoBO getPlatformRecomInfo(Long recomId) throws BusinessException {
        DrMedicationRecomInfo medicationRecomInfo = medicationRecomInfoRepository.findFirstByRecommendId(recomId);
        MedicationRecom medicationRecom = medicationRecomRepository.get(recomId);
        RecomPrescription recomPrescription = recommPrescriptionRepository
                .findFirstByRecommendIdAndTypeOrderByIdDesc(recomId, RecomPrescription.TYPE_PHARMACIST_SIGN);
        log.info("获取处方签名文件：recomId {}, URL {}", recomId, null != recomPrescription ? recomPrescription.getPrescriptionPhotoUrl() : null);
        // 诊断
        DrMedicationRecomDiagnosis recomDiagnose = medicationRecomDiagnosisRepository.findByRecommendId(recomId).get(0);
        DrStandardDiagnosis standardDiagnosis = drStandardDiagnosisRepository.get(recomDiagnose.getDiagnosisId());
        // 用户相关信息
        RecomUserInfoBO recomUserInfoBO = doctorFeignClient.getUserInfoForRecom(medicationRecom.getDoctorId(), medicationRecom.getPatientId(), 0);
        RecomDoctorBO doctorBO = recomUserInfoBO.getDoctor();
        RecomPatientBO patientBO = recomUserInfoBO.getPatient();
        String pdfPath = "/ehp" + recomPrescription.getPrescriptionPhotoUrl();
        // 生成处方图片
        String imgPath = pdfToImg(pdfPath);
        // log.info("处方签名Base64文件 {}", encryptToBase64(imgPath));
        PrescriptionPlatformRecomInfoBO recomInfo = PrescriptionPlatformRecomInfoBO.builder()
                .createdAt(DateUtil.parseDateToString(medicationRecom.getCreatedAt(), DateUtil.DATE_TIME_FORMAT))
                .diagnosisCode(standardDiagnosis.getMainCode())
                .diagnosisName(standardDiagnosis.getName())
                .pharmacistName(medicationRecomInfo.getPharmacistName())
                .pharmacistSignTime(DateUtil.parseDateToString(medicationRecomInfo.getPharmacistSignTime(), DateUtil.DATE_TIME_FORMAT))
                .serialNumber(medicationRecom.getSerialNumber())
                .pdfBase64(encryptToBase64(imgPath))
                .patientIdCard(patientBO.getIdCard())
                .patientName(patientBO.getName())
                .patientPhone(patientBO.getPhone())
                .doctorDepartmentCode(doctorBO.getDepartmentId().toString())
                .doctorDepartmentName(doctorBO.getDepartmentName())
                .doctorName(doctorBO.getName())
                .doctorId(doctorBO.getId())
                .id(medicationRecom.getId())
                .build();

        return recomInfo;
    }

    private String encryptToBase64(String filePath) {
        if (filePath == null) {
            return null;
        }
        try {
            File file = new File(filePath);
            byte[] b = Files.readAllBytes(Paths.get(filePath));
            String contentType = getContentType(filePath);
            // String contentType = "application/pdf";
            String base64EncoderImg = "data:" + contentType + ";base64," + Base64.getEncoder().encodeToString(b);
            return base64EncoderImg;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private String pdfToImg(String pdfPath) {
        String imgPath = pdfPath.replace("pdf", "png");
        File file = new File(pdfPath);
        PDDocument doc = null;
        try {
            doc = PDDocument.load(file);
            PDFRenderer renderer = new PDFRenderer(doc);
            int pageCount = doc.getNumberOfPages();
            for (int i = 0; i < pageCount; i++) {
                BufferedImage image = renderer.renderImageWithDPI(i, 296);
                ImageIO.write(image, "PNG", new File(imgPath));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != doc) {
                    org.apache.pdfbox.cos.COSDocument cos = doc.getDocument();
                    cos.close();
                    doc.close();
                }
            } catch (IOException e) {
                log.info("pdf流关闭异常！");
            }
        }
        return imgPath;
    }

    /**
     * 获取文件ContentType
     *
     * @param fileUrl
     * @return
     */
    public static String getContentType(String fileUrl) {
        String contentType = null;
        Path path = Paths.get(fileUrl);
        try {
            contentType = Files.probeContentType(path);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return contentType;
    }
}
